﻿using System;
using System.IO;

using Commons = NougakudoCompanion.Commons;

namespace NougakuDoController
{
    class Installer
    {
        Commons.Runtime runtime;

        internal Installer(Commons.Runtime runtime)
        {
            this.runtime = runtime;
        }

        /// <summary>
        /// Expand zip files, then configuration NougakuDo.
        /// if error occurs, then rolleback configuration file.
        /// </summary>
        /// <returns></returns>
        internal bool Start()
        {
            bool ret = false;
            if (runtime.Downloads.Count == 0)
            {
                Logging.Write("Installer:Don't need install.", Logging.LogType.INFO);
                ret = Completed();
                return ret;
            }

            ret = UnZip();
            if (ret)
                Logging.Write("Installer:UnZip completed.", Logging.LogType.INFO);
            else
            {
                Logging.Write("Installer:UnZip Error.", Logging.LogType.ERROR);
                return false;
            }
            ret = NougakudoConfig();
            if (ret)
                Logging.Write("Installer:Nougakudo Configuration completed.", Logging.LogType.INFO);
            else
            {
                Logging.Write("Installer:Nougakudo Configuration Error.", Logging.LogType.ERROR);
                return false;
            }
            ret = Completed();
            return ret;
        }

        /// <summary>
        /// Install final process.
        /// </summary>
        /// <returns></returns>
        internal bool Completed()
        {
            try
            {
                File.Copy(Commons.Constants.CONFIGURATION, Commons.Constants.NEW_CONFIG, true);
                File.Delete(Commons.Constants.CONFIGURATION_BACKUP);
                Logging.Write("Installer:Final process completed.", Logging.LogType.INFO);
                return true;
            }
            catch (Exception e)
            {
                Logging.Write("Installer:Final process Error : {0}", new object[] { e.Message }, Logging.LogType.ERROR);
                return false;
            }
        }


        bool UnZip()
        {
            Tuple<bool, string> ret = null;
            string errorMsg = "";
            foreach (var i in runtime.Downloads)
            {
                Logging.Write("Installer:UnZip Start= {0}.", new object[] { i }, Logging.LogType.INFO);
                string sourceZip = Path.Combine(runtime.Environment.DownloadFolder, i + ".zip");
                string targetDir = Path.Combine(runtime.Environment.ApplicationFolder, i);
                if (i == runtime.Environment.Name)
                {
                    targetDir = Path.Combine(runtime.Environment.RuntimeFolder, i);
                }

                // This logic is debug perpose.
                //if (runtime.Environment.UseDevelopmentFabric)
                //    ret = UnZipUtility.UnZipForDevFabric(sourceZip, targetDir, runtime);
                //else
                    ret = UnZipUtility.UnZip(sourceZip, targetDir, runtime);
                if (!ret.Item1)
                {
                    errorMsg = "Installer:UnZip error =" + ret.Item2 + ".";
                    Logging.Write(errorMsg, Logging.LogType.ERROR);
                    return false;
                }
                Logging.Write("Installer:UnZip completed= {0}.", new object[] { i }, Logging.LogType.INFO);
            }
            return true;

        }

        /// <summary>
        /// Create configEnnou.ru and command file for NougakuDo.
        /// </summary>
        /// <returns></returns>
        bool NougakudoConfig()
        {
            //bool ret = false;
            var rubyExecutable = Path.Combine(
                    new string[] { runtime.Environment.RuntimeFolder, runtime.Environment.Name, "bin", Commons.Constants.RUBY });
            foreach (var app in runtime.Applications.Keys)
            {
                Logging.Write("Installer:Nougakudo configuration start= {0}.", new object[] { app }, Logging.LogType.INFO);
                var config = Path.Combine(runtime.Environment.ApplicationFolder, app, Commons.Constants.RACK_CONFIG);
                Nougakudo nougakudo = new Nougakudo(rubyExecutable, config,
                                                    runtime.Applications[app].Environment,
                                                    runtime.Applications[app].NumOfProcess,
                                                    virtualHost: runtime.Applications[app].VirtualHost, // Add for NougakuDo 1.1.0 above.
                                                    hostName: runtime.Environment.VirtualHost           // Add for NougakuDo 1.1.0 above.
                                                    // ennou110: CheckSupportVHsot()                    // Add for sub directory mode.  // Delete to check NougakuDo 1.1.0 above.
                                                    );
                var ret = nougakudo.Generate();
                if (!ret.Item1)
                {
                    foreach (var m in ret.Item2)
                    {
                        Logging.Write("Installer:Nougakudo configuration error ={0}.", new object[] { m }, Logging.LogType.ERROR);
                    }
                    return false;
                }
                Logging.Write("Installer:Nougakudo configuration complete= {0}.", new object[] { app }, Logging.LogType.INFO);
            }
            return true;
        }

        /// <summary>
        /// Delete to check NougakuDo 1.1.0 above.
        /// Check support Virtual Host mode in NougakuDo.
        /// Version >= Constants.VHOST_SUPPORT_VERSION
        /// </summary>
        /// <returns></returns>
        //bool CheckSupportVHsot()
        //{
        //    if (runtime.Environment.Version.Length < 3) return false;
        //    int major_o = 0, minor_o = 0, major_v = 0, minor_v = 0;
        //    int.TryParse(runtime.Environment.Version[0].ToString(), out major_o);
        //    int.TryParse(runtime.Environment.Version[2].ToString(), out minor_o);
        //    int.TryParse(Commons.Constants.VHOST_SUPPORT_VERSION[0].ToString(), out major_v);
        //    int.TryParse(Commons.Constants.VHOST_SUPPORT_VERSION[2].ToString(), out minor_v);
        //    if (major_o > major_v) return true;
        //    else if (major_o == major_v)
        //    {
        //        if (minor_o < minor_v) return false;
        //        else                   return true; 
        //    }
        //
        //    return false;
        //}
    }
}
